/*
 * swTWI_MCP342x.cpp
 *
 *  Created on: 12-09-2014
 *      Author: roper123pl
 *
 */



#include <Arduino.h>
#include <swTWI.h>
#include "swTWI_MCP342x.h"

//extern swTwi swWire;

/*
 * Constructor
 */
swTWI_MCP342x::swTWI_MCP342x() {
	_devAddr = MCP342x_BASE_ADDRESS;			// default base device address
	_cfgReg = 0x90;								// default value config register
}

/*
 * Initiates object to communicate with device
 * and checks if device is connected to the bus.
 *
 * @param device address
 *
 * @return TRUE if device is connected to bus and responds
 */
uint8_t swTWI_MCP342x::begin(uint8_t address) {
	_devAddr = address;							// store device address
	return setConfig();							// set default configuration
												// and if device exists
}

/*
 * Initiates object to communicate with device with default settings
 * and checks if device is connected to the bus.
 *
 * @return TRUE if device is connected to bus and responds
 */
uint8_t swTWI_MCP342x::begin() {
	return begin(MCP342x_BASE_ADDRESS);
}

/*
 * Function send configuration byte to device with settings:
 *   - 16bit resolution,
 *   - gain 1x,
 *   - continuous mode,
 *   - channel 0
 *
 * @return TRUE on success
 */
uint8_t swTWI_MCP342x::setConfig() {
	return setConfig(MCP342x_SIZE_16BIT | MCP342x_GAIN_1X
        			| MCP342x_CHANNEL_0 | MCP342x_MODE_CONTINUOUS);
}

/*
 * Function send configuration byte to device
 *
 * @param device mode to set
 *
 * @return TRUE on success
 */
uint8_t swTWI_MCP342x::setConfig(uint8_t mode) {
	_cfgReg = mode;								// store config register

	swWire.beginTransmission(_devAddr);			// initiate transmission
	swWire.write(_cfgReg | MCP342x_RDY);		// send configuration byte
	return (swWire.endTransmission() == 1);		// end transmission
}

/*
 * Function returns configuration register
 *
 * @return configuration byte
 */
uint8_t swTWI_MCP342x::getConfig() {
	return _cfgReg;
}

/*
 * Function sends byte to device to start conversation
 *
 * @return TRUE on success
 */
uint8_t swTWI_MCP342x::startConversation() {
	swWire.beginTransmission(_devAddr);			// initiate transmission
	swWire.write(_cfgReg | MCP342x_RDY);		// start conversation flag
	return (swWire.endTransmission() == 1);		// end transmission
}

/*
 * Function sends byte to device to start conversation with channel selection
 *
 * @param channel number (allowed values: 0-3)
 *
 * @return TRUE on success
 */
uint8_t swTWI_MCP342x::startConversation(uint8_t channel) {
	_cfgReg &= ~MCP342x_CHANNEL_MASK;			// reseting channel selection
	channel <<= 5;
	_cfgReg |= MCP342x_CHANNEL_MASK & channel;	// selecting new channel
	swWire.beginTransmission(_devAddr);			// initiate transmission
	swWire.write(_cfgReg | MCP342x_RDY);		// start conversation flag
	return (swWire.endTransmission() == 1);		// end transmission
}

uint8_t swTWI_MCP342x::readADC(int32_t* data, uint8_t iter) {
	uint8_t status = 0xFF;
	uint8_t i = 1;
	uint8_t buffer[3] = {0,0,0};
	uint8_t bytesCount;
	uint8_t y = 1;

	*data = 0;
	if ((_cfgReg & MCP342x_SIZE_MASK) == MCP342x_SIZE_18BIT) {
		bytesCount = 4;							// resolution 18bits - 3 bytes
												// + 1 byte for status
	} else {
		bytesCount = 3;							// resolution 16, 14, 12bits - 2 bytes
												// + 1 byte for status
	}
	do	// loop with readings from slave device
		// until bit ~RDY is cleared or 'iter' loops occur
	{
		if (swWire.requestFrom(_devAddr, bytesCount) == bytesCount) {
			for (y = bytesCount-1; y > 0; y--) {
				buffer[y] = swWire.read();		// read byte
			}
			status = swWire.read();				// read last byte with status
		}
		i++;									// increment loop counter
		delay(50);								// wait for ~RDY bit
	} while ((i <= iter) && ((status & MCP342x_RDY) == MCP342x_RDY));
	if ((i > iter) && (status == 0xFF)) {		// check if read successful
		return _cfgReg | MCP342x_RDY;			// return failure status
	}

	// put read bytes into high bytes of output variable
	*data = ((int32_t)buffer[0] << 8) | ((int32_t)buffer[1] << 16) | ((int32_t)buffer[2] << 24);
	if ((status & MCP342x_SIZE_MASK) == MCP342x_SIZE_18BIT) {
		// shift 8bits to left to fill lower 3 bytes and preserve sign bit
		*data >>= 8;
	} else {
		// shift 16bits to left to fill lower 2 bytes and preserve sign bit
		*data >>= 16;
	}

	return status;
}

uint8_t swTWI_MCP342x::readADC(int32_t* data) {
	return readADC(data, 3);
}

